package org.delphy.indy2.views
{
	import caurina.transitions.Tweener;
	
	import flash.display.DisplayObject;
	import flash.display.GradientType;
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.BlurFilter;
	import flash.geom.Matrix;
	import flash.utils.Dictionary;
	
	import mx.containers.ViewStack;
	
	import org.delphy.indy2.views.materials.*;
	import org.papervision3d.cameras.Camera3D;
	import org.papervision3d.objects.Plane;
	import org.papervision3d.scenes.MovieScene3D;

	public class CarbonPresentation3DView extends ViewStack
	{
		
		private var planeArray:Array;
		private var refArray:Array;
		
		private var planeSizeArray:Array;
		private var posArray:Array;
		private var seqArray:Array;
		
		private var refByPlane:Dictionary;
		
		private var superFirstPos:Object;
		private var superLastPos:Object;
		
		private var scene:MovieScene3D;
		private var camera:Camera3D;
		private var viewport:Sprite;
		
		public var segW:Number=6;
		public var segH:Number=6;
		
		public var numDisplayObjects:Number=6;
		
		public var offsetX:Number=200;
		public var offsetZ:Number=100;
		
		private var firstRun:Boolean=true;
		
		public var transitionTime:Number=0.5;
		
		private var shadeSprite:Sprite;
		
		private var lightSprite:Sprite;
		
		public function CarbonPresentation3DView()
		{
			super();
			
			creationPolicy="all";
			
			planeArray=new Array();
			refArray=new Array();
			
			planeSizeArray=new Array();
			posArray=new Array();
			seqArray=new Array();
			
			refByPlane=new Dictionary();
			
			viewport=new Sprite();
			scene=new MovieScene3D(viewport,false);
			
			camera=new Camera3D();
			camera.z=-100;
			
			superFirstPos=new Object();
			superLastPos=new Object();
		}
		
		override public function addChild(child:DisplayObject):DisplayObject{
			var child:DisplayObject=super.addChild(child);
			
			var planeWidth:Number=child.width;
			var planeHeight:Number=child.height;
			var mat:FlexMaterial=new FlexMaterial(child,true);
			var plane:Plane=new Plane(mat,planeWidth,planeHeight,segW,segH);
			
			var refMat:ReflectionFlexMaterial=new ReflectionFlexMaterial(child,true);
			var ref:Plane=new Plane(refMat,planeWidth,planeHeight,segW,segH);
			
			scene.addChild(plane);
			scene.addChild(ref);
			
			planeArray.push(plane);
			refArray.push(ref);
			planeSizeArray.push({width:planeWidth,height:planeHeight});
			
			refByPlane[plane]=ref;
			
			return child;
		}
		
		private function arrangeChildren():void{
			for(var i:uint=0;i<numChildren;i++){
				
				var child:DisplayObject=getChildAt(i);
				child.visible=false;

				var plane:Plane=planeArray[i];
				
				plane.x=getStyle("paddingLeft")+i*offsetX;
				plane.y=-(height-child.height)/2;
				plane.z=i*offsetZ;				
				plane.container.alpha=0;
				
				var ref:Plane=refArray[i];
				
				ref.x=plane.x;
				ref.y=plane.y-child.height-2;
				ref.z=plane.z;
				
				posArray.push({x:plane.x, y:plane.y, z:plane.z});
				seqArray.push(i);
				
				Tweener.addTween(plane.container,{alpha:1,delay:0.2*i, time:2});
			}
			
		}
		
		public function shiftLeft():void{
			var lastSeq:Number=seqArray.pop();
			var newSeq:Array=[lastSeq];
			for(var j:uint=0;j<seqArray.length;j++){
				newSeq.push(seqArray[j]);
			}
			
			seqArray=newSeq;
			
			superFirstPos=getSuperFirstPos(0);
			superLastPos=getSuperLastPos(0);			
			
			var firstIndex:Number=findFirstSeq();
			
			var lastPlane:Plane=planeArray[firstIndex];
			var lastRef:Plane=refArray[firstIndex];
			
			Tweener.addTween(lastPlane,{x:superFirstPos.x, y:superFirstPos.y, z:superFirstPos.z,  
										time:transitionTime/2, onComplete:moveToLastPos, onCompleteParams: [lastPlane,lastRef]});		
			
			Tweener.addTween(lastPlane.container,{alpha:0, time:transitionTime/2});
			
			Tweener.addTween(lastRef,{x:superFirstPos.x, y:superFirstPos.y-planeSizeArray[firstIndex].height-2, z:superFirstPos.z,  
										time:transitionTime/2});		
						
			for(var i:uint=0;i<numChildren;i++){
				if(i==findFirstSeq())
					continue;
				
				var plane:Plane=planeArray[i];
				var pos:Object=posArray[seqArray[i]];
				
				var ref:Plane=refArray[i];
				
				Tweener.addTween(plane,{x:pos.x, y:pos.y, z:pos.z, time:transitionTime});
				Tweener.addTween(ref,{x:pos.x, y:pos.y-planeSizeArray[i].height-2, z:pos.z, time:transitionTime});
			}
		}
		
		private function moveToLastPos(target:Plane,ref:Plane):void{
			target.x=superLastPos.x;
			target.y=superLastPos.y;
			target.z=superLastPos.z;
			
			Tweener.addTween(target,{x:posArray[numChildren-1].x, y:posArray[numChildren-1].y, z:posArray[numChildren-1].z,  time:transitionTime/2});
			Tweener.addTween(target.container,{alpha:1, time:transitionTime/2});
			
			Tweener.addTween(ref,{x:posArray[numChildren-1].x, y:posArray[numChildren-1].y-planeSizeArray[numChildren-1].height-2, z:posArray[numChildren-1].z,  time:transitionTime/2});
		}
		
		private function findFirstSeq():Number{
			for(var i:uint=0;i<numChildren;i++){
				if(seqArray[i]==seqArray.length-1)
					return i;
			}
			
			return -1;
		}
		
		private function getSuperFirstPos(index:Number):Object{
			var firstPos:Object=new Object();
			firstPos.x=posArray[0].x-offsetX;
			firstPos.y=-(height-planeSizeArray[seqArray[index]].height)/2;
			firstPos.z=-offsetZ;	
			
			return firstPos;		
		}
		
		private function getSuperLastPos(index:Number):Object{
			var lastPos:Object=new Object();
			lastPos.x=posArray[numChildren-1]+offsetX;
			lastPos.y=-(height-planeSizeArray[seqArray[index]].height)/2;
			lastPos.z=numChildren*offsetZ;

			return lastPos;			
		}
		
		public function shiftRight():void{
			var firstSeq:Number=seqArray.shift();
			seqArray.push(firstSeq);			

			superFirstPos=getSuperFirstPos(numChildren-1);
			superLastPos=getSuperLastPos(numChildren-1);			
			
			var lastIndex:Number=findLastSeq();
			
			var firstPlane:Plane=planeArray[lastIndex];
			var firstRef:Plane=refArray[lastIndex];
			
			Tweener.addTween(firstPlane,{x:superLastPos.x, y:superLastPos.y, z:superLastPos.z,  
										time:transitionTime/2, onComplete:moveToFirstPos, onCompleteParams: [firstPlane,firstRef]});		
			
			Tweener.addTween(firstPlane.container,{alpha:0, time:transitionTime/2});
			
			Tweener.addTween(firstRef,{x:superLastPos.x, y:superLastPos.y-planeSizeArray[lastIndex].height-2, z:superLastPos.z,  
										time:transitionTime/2});		
			
			for(var i:uint=0;i<numChildren;i++){
				if(i==findLastSeq())
					continue;
					
				var plane:Plane=planeArray[i];
				var pos:Object=posArray[seqArray[i]];
				
				var ref:Plane=refArray[i];
				
				Tweener.addTween(plane,{x:pos.x, y:pos.y, z:pos.z, time:transitionTime});
				Tweener.addTween(ref,{x:pos.x, y:pos.y-planeSizeArray[i].height-2, z:pos.z, time:transitionTime});
			}
		}

		private function moveToFirstPos(target:Plane,ref:Plane):void{
			target.x=superFirstPos.x;
			target.y=superFirstPos.y;
			target.z=superFirstPos.z;
			
			Tweener.addTween(target,{x:posArray[0].x, y:posArray[0].y, z:posArray[0].z,  time:transitionTime/2});
			Tweener.addTween(target.container,{alpha:1, time:transitionTime/2});
			Tweener.addTween(ref,{x:posArray[0].x, y:posArray[0].y-planeSizeArray[0].height-2, z:posArray[0].z,  time:transitionTime/2});
		}


		private function findLastSeq():Number{
			for(var i:uint=0;i<numChildren;i++){
				if(seqArray[i]==0)
					return i;
			}
			
			return -1;
		}
		
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{
			super.updateDisplayList(unscaledWidth,unscaledHeight);
			
			if(firstRun){
				arrangeChildren();
				
				firstRun=false;
			}
			
			applyShade();
			applyClippingMask();
			
			viewport.x=x;
			viewport.y=y;
		}
		
		override protected function createChildren():void{
			super.createChildren();
			
			rawChildren.addChild(viewport);
			
			lightSprite=new Sprite();			
			shadeSprite=new Sprite();
			
			rawChildren.addChild(shadeSprite);
			rawChildren.addChild(lightSprite);			
			
			addEventListener(Event.ENTER_FRAME,renderLoop);
		}
		
		private function renderLoop(evt:Event):void{
			scene.renderCamera(camera);
		}
		
		private function applyShade():void{
			var g:Graphics=shadeSprite.graphics;
			g.clear();
			
			var mat:Matrix=new Matrix();
			mat.createGradientBox(width,height);
			g.beginGradientFill(GradientType.LINEAR,[0,0],[0,1],[200,255],mat);
			g.drawRect(0,0,width,height);
			g.endFill();			
			
			// Spot light
			var lightHeight:Number=80;
			g=lightSprite.graphics;
			g.clear();
			
			mat=new Matrix();
			mat.createGradientBox(width,lightHeight,Math.PI/2);
			g.beginGradientFill(GradientType.LINEAR,[0xffffff,0xffffff],[0,0.3],[0,255],mat);
			g.drawEllipse(0,height-lightHeight,width,lightHeight);
			g.endFill();
			
			var blur:BlurFilter=new BlurFilter();
			blur.blurX=100;
			blur.blurY=60;
			
			lightSprite.filters=[blur];
			
		}
		
		private function applyClippingMask():void{
			var clippingMask:Sprite=new Sprite();
			clippingMask.graphics.clear();
			
			clippingMask.graphics.beginFill(0x000000);
			clippingMask.graphics.drawRect(x,y, width, height);
			
			viewport.mask = clippingMask;
		}
		
	}
}